/*******************************************************************************************
 * Copyright (c) 2006-2009 Alex Robson, Rob Simmons, Craig Israel, and Rachel Twyford
 *
 * Use of this software in any form requires that you have both 
 * read and agreed to the following terms:
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions: 
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the 
 * documentation and/or other materials provided with the distribution.
 * Neither the name of Nvigorate nor the names of its contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ****************************************************************************************/

using System;
using System.Text;

namespace Nvigorate.ConsoleTools
{
	public enum ArgumentError
	{
		Missing,
		Exclusive,
		IllegalValue,
		OutofRange
	}

	[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
	public class Usage : Attribute
	{
		#region Fields

		private bool _optional = false;
		private bool _ignoreCase = false;
		private bool _flag = false;

		private string _name = "";
		private string _description = "";
		private string _legalValues = "";
		private string _ranges = "";

		private string _alternates = "";
		#endregion

		#region Properties

		public string alternates
		{
			get { return _alternates; }
			set { _alternates = value; }
		}

		public bool optional
		{
			get { return _optional; }
			set { _optional = value; }
		}

		public bool ignoreCase
		{
			get { return _ignoreCase; }
			set { _ignoreCase = value; }
		}

		public bool flag
		{
			get { return _flag; }
			set { _flag = value; }
		}

		public string name
		{
			get { return _name; }
			set { _name = value; }
		}

		public string description
		{
			get { return _description; }
			set { _description = value; }
		}

		public string legalValues
		{
			get { return _legalValues; }
			set { _legalValues = value; }
		}

		public string ranges
		{
			get { return _ranges; }
			set { _ranges = value; }
		}

		#endregion

		public override string ToString()
		{
			string primary = "[{0}] - {1}\r\n\t{0} is {2}, {3} parameter that {4}";
			string alternate = "\r\n\tAlternatives:\t[{0}]";
			string values = "\r\n\tLegal Values:\t{0}";
			string ranges = "\r\n\tRanges:\t{0}";
		
			StringBuilder builder = new StringBuilder();

			builder.Append(string.Format(primary,
			                             _name,
			                             _description,
			                            (_optional) ? "an optional" : "a required",
										(_flag) ? "flag" : "value",
										(_ignoreCase) ? "ignores case." : "is case sensitive."));
 		
 			if(_alternates.Length > 0)
 				builder.Append(string.Format(alternate, _alternates.Replace(",","]\r\n\t\t\t[")));
 				
 			if(_legalValues.Length > 0)
				builder.Append(string.Format(values, _legalValues.Replace(",", "\r\n\t\t\t")));
 			
 			if(_ranges.Length > 0)
				builder.Append(string.Format(ranges, _ranges.Replace(",", "\r\n\t\t\t")));

			builder.Append("\r\n");

			return builder.ToString();
		}

		public string GetErrorMessage(ArgumentError error, object value)
		{
			StringBuilder builder = new StringBuilder();

			string header	=	"   [{0}] Argument Usage Error\n";
			string missing =	"      {0} is a required argument\n";
			string alternate =	"      {0} has the following legal alternates:\n           {1}";
			string exclusive =	"      {0} is a mutually exlusive with:\n           {1}";
			string illegal =	"      {0} has a bad value '{2}'. Legal values are:\n           {3}";
			string badrange =	"      {0}'s value '{2}' is out of range. Legal range(s):\n           {4}";
			
			builder.Append(header);
			
			switch(error)
			{
				case ArgumentError.Missing:
					builder.Append(missing);
					break;
				case ArgumentError.Exclusive:
					builder.Append(alternate);
					break;
				case ArgumentError.IllegalValue:
					builder.Append(illegal);
					break;
				case ArgumentError.OutofRange:
					builder.Append(badrange);
					break; 
			}

			return string.Format(builder.ToString(), 
						_name,
						alternates.Replace(",", "\n           "),
						value.ToString(),
						legalValues.Replace(",", "\n           "),
						ranges.Replace(",", "\n           "));
		}

		#region Constructors

		public Usage()
		{
		}

		public Usage(string _description)
		{
			this._description = _description;
		}

		public Usage(string _name, string _description, bool _optional, bool _ignoreCase, bool _flag)
		{
			this._optional = _optional;
			this._ignoreCase = _ignoreCase;
			this._flag = _flag;
			this._name = _name;
			this._description = _description;
		}

		#endregion
	}
}
